package com.uh.microservice.core.service;

import akka.actor.ActorRef;
import akka.actor.ActorSystem;
import com.uh.microservice.core.dto.AkkaMsg;
import com.uh.microservice.core.spring.di.SpringExtension;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.async.DeferredResult;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;

/**
 * 异步服务类
 * Created by liming on 2017/10/10.
 */
@Service
@Scope("singleton")
public class AsyncService {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    private static final Long DEFERRED_RESULT_TIMEOUT = 5000L;

    @Autowired
    private ActorSystem actorSystem;

    @Autowired
    private SpringExtension springExtension;

    int cid=0;
    private int getCmId(){
        return cid++;
    }

    /**
     *  tell 不需要返回值的异步调用入口
     */
    public void tell(AkkaMsg msg){
        ask(msg);
    }

    /**
     *  ask 异步调用一直到获取到返回回调
     */
    public CompletableFuture ask(AkkaMsg msg){
        String beanName="workerActor";
        String actorQueue=String.format("%s-%d-%d",beanName,getCmId(),(int)Math.round(Math.random()*100));
        CompletableFuture<Object> future = new CompletableFuture<>();
        ActorRef workerActor = actorSystem.actorOf(springExtension.props(beanName,future), actorQueue);
        workerActor.tell(msg,ActorRef.noSender());
        logger.debug("AKKA发送数据:",msg.toString());
        return future;
    }

    /**
     *  ask 异步调用一直到直接返回
     */
    public List asks(List<AkkaMsg> list){
        DeferredResult<Object> deferred = new DeferredResult<>(DEFERRED_RESULT_TIMEOUT);
        List<CompletableFuture> futuresList=new ArrayList<CompletableFuture>();
        List resultList=new ArrayList();
        for (AkkaMsg msg: list ) {
            CompletableFuture<Object> funture=ask(msg);
            funture.whenComplete((result,error)->{
                resultList.add(result);
            });
            futuresList.add(funture);
        }

        CompletableFuture allFuturesResult = CompletableFuture.allOf(futuresList.toArray(new CompletableFuture[futuresList.size()]));
        allFuturesResult.join();
        return resultList;
    }
}
